#pragma once

#include <iostream>
#include <cstring>
#include <string>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include <functional>

#include "Log.hpp"  //日志
#include "InetAddr.hpp" 
#include "ThreadPool.hpp"


using namespace LogMudule;
using namespace ThreadPoolModule;

static const int gsocketfd = -1;
static const int gbacklog = 8;
static const int gsize = 4096;
using task_t = std::function<void()>;
using handler_t = std::function<std::string(std::string &)>;

class TcpServer
{
private:
    void Handle(int socketfd)
    {
        LOG(LogLevel::DEBUG) << "进入处理";

        char buffer[gsize]; //读取请求
        std::string package;    //将读取到的请求拼接
        while (1)
        {
            // 读取
            LOG(LogLevel::DEBUG) << "进入读取";
            int n = read(socketfd, buffer, gsize - 1);

            // 读取成功，进行回显
            if (n > 0)
            {
                buffer[n] = 0;
                LOG(LogLevel::DEBUG) << "读取成功：" << buffer;
                package += buffer;
                std::string res = _handler(package);    //对请求报文进行处理，并返回结果
                if (!res.empty())
                {
                    //发送
                    int m = send(socketfd, res.c_str(), res.size(), 0);
                    if (m < 0)
                    {
                        LOG(LogLevel::ERROR) << "send err...";
                        break;
                    }
                }
            }
            // 客户端退出
            else if (n == 0)
            {
                LOG(LogLevel::DEBUG) << "用户退出";
                break;
            }
            // 出错
            else
            {
                LOG(LogLevel::ERROR) << "read err...";
                printf("Error occurred: %d (%s)\n", errno, strerror(errno));
                break;
            }
        }

        int n = ::close(socketfd);
        (void)n;
    }

public:
    TcpServer(uint16_t port, handler_t handler)
        : _port(port),
          _listenfd(gsocketfd),
          _addr(port),
          _handler(handler)
    {
    }

    void InitServer()
    {

        LOG(LogLevel::DEBUG) << "准备进行初始化";
        // 1.创建socket
        _listenfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_listenfd < 0)
        {
            LOG(LogLevel::ERROR) << "socket err...";
            return;
        }

        LOG(LogLevel::DEBUG) << "socket : " << _listenfd << "端口号：" << _addr.GetProt();
        // 2.绑定
        int n = ::bind(_listenfd, _addr.GetAddr(), _addr.Addr_size());
        if (n < 0)
        {
            LOG(LogLevel::ERROR) << "bind err...";
            return;
        }

        // 3.设置为监听
        n = ::listen(_listenfd, gbacklog);
        if (n < 0)
        {
            LOG(LogLevel::ERROR) << "listen err...";
            return;
        }

        LOG(LogLevel::DEBUG) << "完成初始化";
    }

    void Start()
    {
        LOG(LogLevel::DEBUG) << "启动服务";

        while (1)
        {
            // 1.获取新的套接字
            struct sockaddr_in tmp;
            ::bzero(&tmp, sizeof(tmp));
            socklen_t len = sizeof(tmp);
            int socketfd = ::accept(_listenfd, (struct sockaddr *)&tmp, &len);
            if (socketfd < 0)
            {
                continue;
            }

            LOG(LogLevel::DEBUG) << "新套接字：" << socketfd;
            // 2.读取+处理+回显

            // 只能处理单个客户端
            // Handle(socketfd);

            // 多进程版本
            //  pid_t id = fork();
            //  if(id == 0)
            //  {
            //      //关闭不用的文件描述符
            //      ::close(_listenfd);

            //     //让孙子进程处理，子进程退出
            //     if(fork() > 0)
            //     {
            //         exit(0);
            //     }

            //     Handle(socketfd);
            //     exit(0);
            // }

            // int rid = ::waitpid(id,nullptr,0);
            // if(rid < 0)
            // {
            //      LOG(LogLevel::ERROR) << "waitpid err...";
            // }

            // 多线程版本
            ThreadPool<task_t>::getInstance()->Equeue([this, socketfd]()
                                                      { this->Handle(socketfd); });
            LOG(LogLevel::DEBUG) << "加入线程池";
        }
    }

    ~TcpServer() = default;

private:
    int _listenfd;
    uint16_t _port;
    InetAddr _addr;

    handler_t _handler;
};